//**************************************************
// Description: check dst_IP , hard_type and prot_type
//**************************************************

//**************************************************
// include files
//**************************************************
`include "protocol_define.v"

module ARP_deal #(
    parameter                       ARP_SET_HARD_TYPE   = 1         ,
    parameter                       ARP_SET_PROT_TYPE   = 16'h0800  ,
    parameter                       ARP_SET_HARD_LEN    = 6         ,
    parameter                       ARP_SET_PROT_LEN    = 4         ,
    parameter                       ARP_SET_OP          = 1         ,
    parameter                       ARP_GEN_HARD_TYPE   = 1         ,
    parameter                       ARP_GEN_PROT_TYPE   = 16'h0800  ,
    parameter                       ARP_GEN_HARD_LEN    = 6         ,
    parameter                       ARP_GEN_PROT_LEN    = 4         ,
    parameter                       ARP_GEN_OP          = 2 
    )(
    input                           clk ,
    input                           rst_n ,
    // pre-module(unpack) interface
    // ARP content
    input                           ARP_enable ,
    input   [15:0]                  ARP_hard_type ,
    input   [15:0]                  ARP_prot_type ,
    input   [7:0]                   ARP_hard_len ,
    input   [7:0]                   ARP_prot_len ,
    input   [15:0]                  ARP_op ,
    input   [47:0]                  ARP_src_mac ,
    input   [31:0]                  ARP_src_ip ,
    input   [47:0]                  ARP_dst_mac ,
    input   [31:0]                  ARP_dst_ip ,
    // MAC content
    input   [47:0]                  DATALINK_src_mac ,
    input   [47:0]                  DATALINK_dst_mac ,
    // post_module(ARP gen) interface
    // ARP content
    output                          ARP_gen_enable ,
    output  [15:0]                  ARP_gen_hard_type ,
    output  [15:0]                  ARP_gen_prot_type ,
    output  [7:0]                   ARP_gen_hard_len ,
    output  [7:0]                   ARP_gen_prot_len ,
    output  [15:0]                  ARP_gen_op ,
    output  [47:0]                  ARP_gen_src_mac ,
    output  [31:0]                  ARP_gen_src_ip ,
    output  [47:0]                  ARP_gen_dst_mac ,
    output  [31:0]                  ARP_gen_dst_ip ,
    // MAC content
    output  [47:0]                  DATALINK_gen_src_mac ,
    output  [47:0]                  DATALINK_gen_dst_mac ,
    // NP config register
    input   [47:0]                  NP_MAC_address ,
    input   [31:0]                  NP_IP_address
) ;
//**************************************************
// FSM
//**************************************************
    //----------------------------------------------
    // signal declare
    //----------------------------------------------
    // check result
    reg                     ARP_head_check_result ;
    reg                     ARP_head_check_success ;
    // pre-signal delay
    // reg     [15:0]          ARP_hard_type_ff1 ;
    // reg     [15:0]          ARP_prot_type_ff1 ;
    // reg     [7:0]           ARP_hard_len_ff1 ;
    // reg     [7:0]           ARP_prot_len_ff1 ;
    // reg     [15:0]          ARP_op_ff1 ;
    reg     [47:0]          ARP_src_mac_ff1 ;
    reg     [31:0]          ARP_src_ip_ff1 ;
    reg     [47:0]          ARP_dst_mac_ff1 ;
    reg     [31:0]          ARP_dst_ip_ff1 ;
    reg     [47:0]          DATALINK_src_mac_ff1 ;
    reg     [47:0]          DATALINK_dst_mac_ff1 ;
    // post-signal declare
    reg                     ARP_gen_enable_r ;
    reg     [15:0]          ARP_gen_hard_type_r ;
    reg     [15:0]          ARP_gen_prot_type_r ;
    reg     [7:0]           ARP_gen_hard_len_r ;
    reg     [7:0]           ARP_gen_prot_len_r ;
    reg     [15:0]          ARP_gen_op_r ;
    reg     [47:0]          ARP_gen_src_mac_r ;
    reg     [31:0]          ARP_gen_src_ip_r ;
    reg     [47:0]          ARP_gen_dst_mac_r ;
    reg     [31:0]          ARP_gen_dst_ip_r ;
    reg     [47:0]          DATALINK_gen_src_mac_r ;
    reg     [47:0]          DATALINK_gen_dst_mac_r ;

    //----------------------------------------------
    // FSM declare
    //----------------------------------------------
    localparam ARP_DEAL_IDLE    = 2'd0 ;
    localparam ARP_DEAL_CHECK   = 2'd1 ;
    localparam ARP_DEAL_TRANS   = 2'd2 ;
    localparam ARP_DEAL_END     = 2'd3 ;
    reg[1:0]    arp_deal_state_c ;
    reg[1:0]    arp_deal_state_n ;

    // FSM(1)
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)
            arp_deal_state_c <= ARP_DEAL_IDLE ;
        else 
            arp_deal_state_c <= arp_deal_state_n ;
    end
    // FSM(2)
    always @(*) begin
        case (arp_deal_state_c)
            ARP_DEAL_IDLE: begin
                if( ARP_enable ) 
                    arp_deal_state_n = ARP_DEAL_CHECK ;
                else
                    arp_deal_state_n = ARP_DEAL_IDLE ;
            end 

            ARP_DEAL_CHECK: begin
                if( ARP_head_check_result ) begin
                    if( ARP_head_check_success )
                        arp_deal_state_n = ARP_DEAL_TRANS ;
                    else
                        arp_deal_state_n = ARP_DEAL_END ;
                end
                else
                    arp_deal_state_n = ARP_DEAL_CHECK ;
            end

            ARP_DEAL_TRANS: begin
                arp_deal_state_n = ARP_DEAL_END ;
            end

            ARP_DEAL_END: begin
                arp_deal_state_n = ARP_DEAL_IDLE ;
            end

            default: 
                arp_deal_state_n = ARP_DEAL_IDLE ;
        endcase
    end
    // FSM(3)
    // dest IP check
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) 
            ARP_head_check_result <= 1'b0 ;
        else if( (arp_deal_state_c == ARP_DEAL_IDLE) && (ARP_enable) )
            ARP_head_check_result <= 1'b1 ;
        else 
            ARP_head_check_result <= 1'b0 ;
    end
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)
            ARP_head_check_success <= 1'b0 ;
        else if( ((arp_deal_state_c == ARP_DEAL_IDLE) && (ARP_enable)) &&
                    (ARP_hard_type  == ARP_SET_HARD_TYPE    ) &&
                    (ARP_prot_type  == ARP_SET_PROT_TYPE    ) &&
                    (ARP_hard_len   == ARP_SET_HARD_LEN     ) &&
                    (ARP_prot_len   == ARP_SET_PROT_LEN     ) &&
                    (ARP_op         == ARP_SET_OP           ) &&
                    (ARP_dst_ip     == NP_IP_address        ) )
            ARP_head_check_success <= 1'b1 ;
        else
            ARP_head_check_success <= 1'b0 ;
    end
    // gen tx field 
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            ARP_gen_enable_r            <= {(1){1'b0}} ;
            ARP_gen_hard_type_r         <= {(16){1'b0}} ;
            ARP_gen_prot_type_r         <= {(16){1'b0}} ;
            ARP_gen_hard_len_r          <= {(8){1'b0}} ;
            ARP_gen_prot_len_r          <= {(8){1'b0}} ;
            ARP_gen_op_r                <= {(16){1'b0}} ;
            ARP_gen_src_mac_r           <= {(48){1'b0}} ;
            ARP_gen_src_ip_r            <= {(32){1'b0}} ;
            ARP_gen_dst_mac_r           <= {(48){1'b0}} ;
            ARP_gen_dst_ip_r            <= {(32){1'b0}} ;
            DATALINK_gen_src_mac_r      <= {(48){1'b0}} ;
            DATALINK_gen_dst_mac_r      <= {(48){1'b0}} ;
        end
        else if( arp_deal_state_c == ARP_DEAL_TRANS ) begin
            ARP_gen_enable_r            <= 1'b1 ;
            ARP_gen_hard_type_r         <= ARP_GEN_HARD_TYPE    ;
            ARP_gen_prot_type_r         <= ARP_GEN_PROT_TYPE    ;
            ARP_gen_hard_len_r          <= ARP_GEN_HARD_LEN     ;
            ARP_gen_prot_len_r          <= ARP_GEN_PROT_LEN     ;
            ARP_gen_op_r                <= ARP_GEN_OP           ;
            ARP_gen_src_mac_r           <= NP_MAC_address       ;
            ARP_gen_src_ip_r            <= ARP_dst_ip_ff1       ;
            ARP_gen_dst_mac_r           <= ARP_src_mac_ff1      ;
            ARP_gen_dst_ip_r            <= ARP_src_ip_ff1       ;
            DATALINK_gen_src_mac_r      <= DATALINK_dst_mac_ff1 ;
            DATALINK_gen_dst_mac_r      <= DATALINK_src_mac_ff1 ;
        end
        else begin
            ARP_gen_enable_r            <= 1'b0                     ;
            ARP_gen_hard_type_r         <= ARP_gen_hard_type_r      ;
            ARP_gen_prot_type_r         <= ARP_gen_prot_type_r      ;
            ARP_gen_hard_len_r          <= ARP_gen_hard_len_r       ;
            ARP_gen_prot_len_r          <= ARP_gen_prot_len_r       ;
            ARP_gen_op_r                <= ARP_gen_op_r             ;
            ARP_gen_src_mac_r           <= ARP_gen_src_mac_r        ;
            ARP_gen_src_ip_r            <= ARP_gen_src_ip_r         ;
            ARP_gen_dst_mac_r           <= ARP_gen_dst_mac_r        ;
            ARP_gen_dst_ip_r            <= ARP_gen_dst_ip_r         ;
            DATALINK_gen_src_mac_r      <= DATALINK_gen_src_mac_r   ;
            DATALINK_gen_dst_mac_r      <= DATALINK_gen_dst_mac_r   ;
        end
    end

    // input signal delay
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            // ARP_hard_type_ff1           <= {(16){1'b0}} ;
            // ARP_prot_type_ff1           <= {(16){1'b0}} ;
            // ARP_hard_len_ff1            <= {(8){1'b0}} ;
            // ARP_prot_len_ff1            <= {(8){1'b0}} ;
            // ARP_op_ff1                  <= {(16){1'b0}} ;
            ARP_src_mac_ff1             <= {(48){1'b0}} ;
            ARP_src_ip_ff1              <= {(32){1'b0}} ;
            ARP_dst_mac_ff1             <= {(48){1'b0}} ;
            ARP_dst_ip_ff1              <= {(32){1'b0}} ;
            DATALINK_src_mac_ff1        <= {(48){1'b0}} ;
            DATALINK_dst_mac_ff1        <= {(48){1'b0}} ;
        end
        else if( (arp_deal_state_c == ARP_DEAL_IDLE) && ARP_enable ) begin
            // ARP_hard_type_ff1           <= ARP_hard_type    ;
            // ARP_prot_type_ff1           <= ARP_prot_type    ;
            // ARP_hard_len_ff1            <= ARP_hard_len     ;
            // ARP_prot_len_ff1            <= ARP_prot_len     ;
            // ARP_op_ff1                  <= ARP_op           ;
            ARP_src_mac_ff1             <= ARP_src_mac      ;
            ARP_src_ip_ff1              <= ARP_src_ip       ;
            ARP_dst_mac_ff1             <= ARP_dst_mac      ;
            ARP_dst_ip_ff1              <= ARP_dst_ip       ;
            DATALINK_src_mac_ff1        <= DATALINK_src_mac ;
            DATALINK_dst_mac_ff1        <= DATALINK_dst_mac ;
        end
        else begin
            // ARP_hard_type_ff1           <= ARP_hard_type_ff1    ;
            // ARP_prot_type_ff1           <= ARP_prot_type_ff1    ;
            // ARP_hard_len_ff1            <= ARP_hard_len_ff1     ;
            // ARP_prot_len_ff1            <= ARP_prot_len_ff1     ;
            // ARP_op_ff1                  <= ARP_op_ff1           ;
            ARP_src_mac_ff1             <= ARP_src_mac_ff1      ;
            ARP_src_ip_ff1              <= ARP_src_ip_ff1       ;
            ARP_dst_mac_ff1             <= ARP_dst_mac_ff1      ;
            ARP_dst_ip_ff1              <= ARP_dst_ip_ff1       ;
            DATALINK_src_mac_ff1        <= DATALINK_src_mac_ff1 ;
            DATALINK_dst_mac_ff1        <= DATALINK_dst_mac_ff1 ;
        end
    end

    // output assign
    assign ARP_gen_enable           = ARP_gen_enable_r ;
    assign ARP_gen_hard_type        = ARP_gen_hard_type_r ;
    assign ARP_gen_prot_type        = ARP_gen_prot_type_r ;
    assign ARP_gen_hard_len         = ARP_gen_hard_len_r ;
    assign ARP_gen_prot_len         = ARP_gen_prot_len_r ;
    assign ARP_gen_op               = ARP_gen_op_r ;
    assign ARP_gen_src_mac          = ARP_gen_src_mac_r ;
    assign ARP_gen_src_ip           = ARP_gen_src_ip_r ;
    assign ARP_gen_dst_mac          = ARP_gen_dst_mac_r ;
    assign ARP_gen_dst_ip           = ARP_gen_dst_ip_r ;
    assign DATALINK_gen_src_mac     = DATALINK_gen_src_mac_r ;
    assign DATALINK_gen_dst_mac     = DATALINK_gen_dst_mac_r ;
endmodule